/*!
 * Scrollbar - 1.0.0 - 2013-08
 * http://github.com/yanxyz/scrollbar
 * Licensed under the MIT License
 */
;
(function($) {
    var defaults = {
        content: '.scroller', // jQuery selector 内容区
        axis: 'Y', // X||Y 滚动条方向，水平或竖直
        scroll: true, // bool 是否可以滚动
        wheel: 40, // number 每次滚动距离 px
        lockscroll: true, // 滚动到终点后将滚动交给浏览器
        invertscroll: false // 移动端滚动
    }

    $.fn.scrollbar = function(opts) {
        var options = $.extend({}, defaults, opts)

        return this.each(function() {
            new Scrollbar($(this), options)
        })
    }

    /**
     * Scrollbar 构造函数
     *
     * @param {[jQuery object]} 外部容器，属性 overflow:hidden
     * @param {[plain object]} 选项
     *
     * 下面注释说明以 height 为例
     */

    function Scrollbar(root, options) {
        var _this = this,
            // 滚动方向
            _axis = options.axis,
            _isX = _axis === 'X',
            _pos = _isX ? 'left' : 'top',
            // 首字母大小方便用于 offsetHeight, 用于 height 时需转为小写
            _size = _isX ? 'Width' : 'Height',
            _scroll = 0, // 滚动距离
            _position = {
                start: 0,
                now: 0
            },
            _mouse = {},
            hasTouchEvents = 'ontouchstart' in document.documentElement,
            // jQuery object
            $doc = $(document),
            $body = $('body'),
            $outer = root,
            $inner = $(options.content, root),
            $scrollbar = $('.scrollbar', root);

        if ($inner.length === 0) {
            if (window.console) {
                console.log('please check' + options.content)
            }
            return _this
        }

        // 自动插入滚动条，可以事先添加
        if ($scrollbar.length === 0) {
            $scrollbar = $('<div class="scrollbar"><div class="scrollbar-track"></div><div class="scrollbar-thumb"></div></div>').appendTo(root)
        }

        var $track = $('.scrollbar-track', $scrollbar),
            $thumb = $('.scrollbar-thumb', $scrollbar);

        function initialize() {
            update();
            addEvents();
            // 显式返回此对象，不然构造函数返回普通对象
            return _this;
        }

        function update(sScroll) {
            var s = _size.toLowerCase(),
                tracksize = parseInt($track.css(s), 10),
                thumbsize = parseInt($thumb.css(s), 10);

            $outer[_axis] = $outer[0]['client' + _size];
            $inner[_axis] = $inner[0]['scroll' + _size];
            $inner.ratio = $outer[_axis] / $inner[_axis];
            // 滚动条显示隐藏
            $scrollbar.toggleClass('disable', $inner.ratio >= 1);

            // 滑轨，如果没有指定高度，则取视口的高度
            $track[_axis] = tracksize ? tracksize : $outer[_axis];
            // 滑块，如果没有指定高度，则取视口的百分比高度
            $thumb[_axis] = Math.min($track[_axis], Math.max(0, (
                thumbsize ? thumbsize : ($track[_axis] * $inner.ratio))));
            // _scroll/$inner[_axis] = x/$track[_axis]，x 为滑块滚动距离
            $scrollbar.ratio = thumbsize ?
                ($inner[_axis] - $outer[_axis]) / ($track[_axis] - $thumb[_axis]) :
                ($inner[_axis] / $track[_axis]);

            setSize();
        };

        function setSize() {
            var s = _size.toLowerCase();
            // 滚动条宽度同
            $scrollbar.css(s, $track[_axis]);
            $track.css(s, $track[_axis]);
            $thumb.css(s, $thumb[_axis]);

            $inner.css(_pos, -_scroll);
            $thumb.css(_pos, _scroll / $scrollbar.ratio);
            _mouse.start = $thumb.offset()[_pos];
        }

        function addEvents() {
            if (options.scroll) {
                wheelEvent = "onwheel" in document.createElement("div") ? "wheel" :
                    document.onmousewheel !== undefined ? "mousewheel" :
                    "DOMMouseScroll"
                $outer.on(wheelEvent, wheelHandler)
            }

            if (!hasTouchEvents) {
                $thumb.on('mousedown', start);
                $track.on('mouseup', drag);
            } else {
                $outer.ontouchstart = function(event) {
                    if (1 === event.touches.length) {
                        start(event.touches[0]);
                        event.stopPropagation();
                    }
                };
            }
        }

        function wheelHandler(e) {
            if ($inner.ratio < 1) {
                var event = e.originalEvent,
                    // 增量只关注正负，即方向
                    delta = event.wheelDelta ? event.wheelDelta / 120 : -event.detail / 3;

                _scroll -= delta * options.wheel;
                _scroll = Math.min(($inner[_axis] - $outer[_axis]), Math.max(0, _scroll));
                $inner.css(_pos, -_scroll);
                $thumb.css(_pos, _scroll / $scrollbar.ratio);

                if (options.lockscroll || (_scroll !== ($inner[_axis] - $outer[_axis]) && _scroll !== 0)) {
                    e.preventDefault();
                }
            }
        }

        function start(e) {
            $body.addClass("noSelect");

            _mouse.start = _isX ? e.pageX : e.pageY;

            var oThumbDir = parseInt($thumb.css(_pos), 10);
            _position.start = oThumbDir == 'auto' ? 0 : oThumbDir;

            if (!hasTouchEvents) {
                $doc.on({
                    'mousemove': drag,
                    'mouseup': end
                });
                $thumb.on('mouseup', end);
            } else {
                document.ontouchmove = function(event) {
                    event.preventDefault();
                    drag(event.touches[0]);
                };
                document.ontouchend = end;
            }

            e.preventDefault();
        }

        function drag(event) {
            if ($inner.ratio < 1) {
                if (options.invertscroll && hasTouchEvents) {
                    _position.now = Math.min(
                        ($track[_axis] - $thumb[_axis]),
                        Math.max(0, (_position.start + (_mouse.start - (_isX ? event.pageX : event.pageY))))
                    );
                } else {
                    _position.now = Math.min(
                        ($track[_axis] - $thumb[_axis]),
                        Math.max(0, (_position.start + ((_isX ? event.pageX : event.pageY) - _mouse.start)))
                    );
                }

                _scroll = _position.now * $scrollbar.ratio;
                $inner.css(_pos, -_scroll);
                $thumb.css(_pos, _position.now);
            }
        }

        function end() {
            $body.removeClass("noSelect");
            $doc.off('mousemove', drag);
            $doc.off('mouseup', end);
            $thumb.off('mouseup', end);
            document.ontouchmove = document.ontouchend = null;
        }

        return initialize();
    }

}(jQuery));
